<?php
declare(strict_types=1);

namespace Service\FaceService;

use Service\Code\Normal;
use Service\BaseService;
use Service\VenderClient\FacePlus\FacePlusApi;
use Service\ConfigureService\ChannelConfigService;
use App\Model\BbcModel\Face;
use App\Model\BbcModel\Faceset;
use App\Amqp\Producer\FaceCenterMessageProducer;
use Hyperf\Utils\ApplicationContext;
use Hyperf\Amqp\Producer;
use Service\ShareCenterService\ShareCenterService;
use Service\Code\CodeBuilder;
use Service\MemberService\MemberService;
use App\Model\BbcModel\Order;
use App\Model\BbcModel\OrderExtends;
use Service\AreaService\AreaService;
use App\Model\BbcModel\Mnuser;

class FaceService extends BaseService
{
    /**
     * 识别身份证
     * @param array $param
     * @return type
     */
    public function ocrIdCard(int $cid,array $param) {
        if(!isset($param['image_base64'])||empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $faceconfig = ChannelConfigService::instance()->getChannelConfig('faceplus_config', $cid);
        if(empty($faceconfig)){
            return Normal::returnCode(Normal::FAIL, 'face++参数未配置');
        }
        $response=(new FacePlusApi($faceconfig))->ocrIdCard($param);        
        if($response['code']!= Normal::SUC){
            return $response;
        }
        if(empty($response['data']['cards'])){
            return Normal::returnCode(Normal::FAIL, '未识别到身份证');
        }
        $card=$response['data']['cards'][0];
        if($card['side']=='back'){
            return Normal::returnCode(Normal::FAIL, '非身份证正面');
        }
        $data=[
            'name'=>$card['name'],
            'address'=>$card['address'],
            'idcard'=>$card['id_card_number'],
            'gender'=>$card['gender'],
            'birthday'=>$card['birthday'],
            'race'=>$card['race']
        ];
        $area= AreaService::instance()->getAreaByIdcard($card['id_card_number']);
        $returnData= array_merge($data,$area);
        return   Normal::returnCode(Normal::SUC, '识别成功',$returnData);
    }
    
    /**
     * 根据身份证号码返回省市区地址
     * @param type $param
     * @return type
     */
    public function getAreaByIdcard(array $param) {
        
        if(empty($param['idcard'])){
            return   Normal::returnCode(Normal::FAIL, '身份证好必传');
        }
        $area= AreaService::instance()->getAreaByIdcard($param['idcard']);
        return   Normal::returnCode(Normal::SUC, '识别成功',$area);
    }
    
    /**
     * 人脸检测
     * @param array $param
     * @return type
     */
    public function faceCheck(int $cid,int $mn_sid,array $param) {
        if(!isset($param['image_base64'])||empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $faceconfig = ChannelConfigService::instance()->getChannelConfig('faceplus_config', $cid);
        if(empty($faceconfig)){
            return Normal::returnCode(Normal::FAIL, 'face++参数未配置');
        }
        $response=(new FacePlusApi($faceconfig))->faceCheck($param);        
        if($response['code']!= Normal::SUC){
            return $response;
        }
        if(empty($response['data']['faces'])){
            return Normal::returnCode(Normal::FAIL,'未检测出人脸头像,请重新识别',$response);
        }
        if($response['data']['face_num']!=1){
            return Normal::returnCode(Normal::FAIL,'人像识别包含多人头像,请重新识别',$response);
        }
        $face=$response['data']['faces'][0];
        if($face['attributes']['facequality']['value']<=$face['attributes']['facequality']['threshold']){
            return Normal::returnCode(Normal::FAIL,'人像识别图片质量欠佳,请重新识别',$response);
        }
        $data=[
            'face_token'=>$face['face_token'],
            'facequality'=>$face['attributes']['facequality'],
            'beauty'=>$face['attributes']['beauty']
        ];
        $messageData=[
            'actionType'=>'add',
            'cid'       =>$cid,
            'mn_sid'    =>$mn_sid,
            'face_token'=>$face['face_token'],
            'image_base64'=>$param['image_base64']
        ];
        Face::instance()->add([
            'cd'=>time(),
            'cid'=>$cid,
            'face_token'=>$face['face_token'],
            'image_base64'=>$param['image_base64'],
            'mn_sid'=>$mn_sid
        ]);
        $this->publishMsg($messageData);        
        return   Normal::returnCode(Normal::SUC, '识别成功',$data);
    }
    
    /**
     * 人脸绑定
     * @param int $cid
     * @param int $mn_sid
     * @param array $param
     * @return type
     */
    public function faceBind(int $cid,int $mn_sid,array $param) {
        if(!isset($param['face_token'])||empty($param['face_token'])){
            return Normal::returnCode(Normal::FAIL,'face_token必传');
        }
        $mnuser= Mnuser::instance()->info(['id'=>$mn_sid]);
        if($mnuser['type']==3){
            if(!isset($param['true_name'])||empty($param['true_name'])){
                return Normal::returnCode(Normal::FAIL,'true_name必传');
            }
            if(!isset($param['idcard'])||empty($param['idcard'])){
                return Normal::returnCode(Normal::FAIL,'idcard必传');
            }
        }
        if(!isset($param['mobile'])||empty($param['mobile'])){
            return Normal::returnCode(Normal::FAIL,'mobile必传');
        }
        $face_token=$param['face_token'];
        $facerep=Face::instance()->info(['cid'=>$cid,'mobile'=>$param['mobile']]);
        if($facerep&&$facerep['face_token']!=$face_token){
            return Normal::returnCode(Normal::FAIL,'该手机号已绑定其他面部信息');
        }
        $face= Face::instance()->info(['cid'=>$cid,'face_token'=>$face_token]);
        if(empty($face)){
            return Normal::returnCode(Normal::FAIL,'未找到该面部信息');
        }
        $faceset_id=$face['faceset_id'];
        $messageData=[
            'actionType'=>'edit',
            'cid'       =>$cid,
            'mn_sid'    =>$mn_sid,
            'face_token'=>$face['face_token'],
            'mobile'=>$param['mobile'],
        ];
        $faceEditData=[
            'faceset_id'=>$faceset_id,
            'mobile'=>$param['mobile'],
            'md'=>time()
        ];
        if(isset($param['true_name'])&&!empty($param['true_name'])){
            $messageData['name']=$param['true_name'];
            $faceEditData['name']=$param['true_name'];
        }
        if(isset($param['idcard'])&&!empty($param['idcard'])){
            $messageData['idcard']=$param['idcard'];
            $faceEditData['idcard']=$param['idcard'];
        }
        if($faceset_id==0){
            $addFace= $this->addFace($cid, $face_token);
            if($addFace['code']!= Normal::SUC){
                return $addFace;
            }
            $faceset_id=$addFace['data']['faceset_id'];
        }
        $faceEditData['faceset_id']=$faceset_id;
        Face::instance()->edit(['id'=>$face['id']],$faceEditData);
        $this->publishMsg($messageData);
        return Normal::returnCode(Normal::SUC, '绑定成功');
    }
    
    /**
     * 人脸库添加人脸，如果人脸库不存在则自动创建人脸库，每个人脸库限制最大数量9900
     * @param int $cid
     * @param string $face_token
     * @return type
     */
    public function addFace(int $cid,string $face_token) {
        $faceconfig = ChannelConfigService::instance()->getChannelConfig('faceplus_config', $cid);
        if(empty($faceconfig)){
            return Normal::returnCode(Normal::FAIL, 'face++参数未配置');
        }
        $facesetWhere=[
            ['cid','=',$cid],
            ['total','<=',9900],
            '_order_'=>['total'=>'DESC']
        ];
        $faceset= Faceset::instance()->info($facesetWhere);
        if($faceset){
            $faceset_id=$faceset['id'];
            $addFaceData=[
                'faceset_token'=>$faceset['faceset_token'],
                'face_tokens'=>$face_token
            ];
            $responseAddFace=(new FacePlusApi($faceconfig))->addFace($addFaceData);        
            if($responseAddFace['code']!= Normal::SUC){
                return $responseAddFace;
            }
        }else{
            $sn=CodeBuilder::getCode($cid);
            $addFaceSetData=[
                'outer_id'=>$sn,
                'display_name'=>$sn,
                'face_tokens'=>$face_token
            ];
            $responseAddFaceSet=(new FacePlusApi($faceconfig))->createFaceStorage($addFaceSetData);        
            if($responseAddFaceSet['code']!= Normal::SUC){
                return $responseAddFaceSet;
            }
            if(isset($responseAddFaceSet['data']['faceset_token'])){
                $facesetAddData=[
                    'cd'=>time(),
                    'cid'=>$cid,
                    'faceset_token'=>$responseAddFaceSet['data']['faceset_token'],
                    'outer_id'=>$sn,
                    'display_name'=>$sn,
                ];
                $faceset_id=Faceset::instance()->add($facesetAddData);
            }
            if($responseAddFaceSet['data']['face_added']!=1){
                return Normal::returnCode(Normal::FAIL, '添加失败');
            }
        }
        Faceset::instance()->where(['id'=>$faceset_id])->increment('total',1);
        return Normal::returnCode(Normal::SUC, '操作成功',['faceset_id'=>$faceset_id]);
    }
    
    /**
     * 人脸库搜索，并大搜索多库，如果搜索到，则根据搜索到的人脸，查询到手机号，并返回该号会员信息
     * @param int $cid
     * @param int $mn_sid
     * @param array $param
     * @return type
     */
    public function faceSearch(int $cid,int $mn_sid,array $param) {
        if(!isset($param['image_base64'])||empty($param['image_base64'])){
            return Normal::returnCode(Normal::FAIL,'图片的base64加密的二进制数据必传');
        }
        $faceconfig = ChannelConfigService::instance()->getChannelConfig('faceplus_config', $cid);
        if(empty($faceconfig)){
            return Normal::returnCode(Normal::FAIL, 'face++参数未配置');
        }
        $faceset= Faceset::instance()->lists(['cid'=>$cid]);
        if(empty($faceset)){
            return Normal::returnCode(Normal::FAIL, '还未存储过任何人脸信息');
        }
        $faceset_tokens= array_column($faceset, 'faceset_token');
        $searchData=[
            'faceset_tokens'=>$faceset_tokens,
            'image_base64'=>$param['image_base64']
        ];
        $responseAddFace=(new FacePlusApi($faceconfig))->searchStorages($searchData);        
        if($responseAddFace['code']!= Normal::SUC){
            return $responseAddFace;
        }
        $score=$responseAddFace['data']['score'];
        $scoredata=$responseAddFace['data']['scoredata'];
        rsort($score);
        $face_token=$scoredata[(string)$score[0]];
        if(!isset($face_token)||empty($face_token)){
            return Normal::returnCode(Normal::FAIL, '未识别到搜索的人脸');
        }
        $face= Face::instance()->info(['cid'=>$cid,'face_token'=>$face_token]);
        if(empty($face)){
            return Normal::returnCode(Normal::FAIL, '未查询到人脸');
        }
        $mobile=$face['mobile'];
        $member=MemberService::instance()->getMemberInfo($cid, $mn_sid, ['account'=>$mobile]);
        $order= Order::instance()->info([
            'cid'           => $cid,
            'buyer_mobile'  => $mobile,
            '_order_'       =>['cd'=>'desc']
        ]);
        $express_type=2;
        $orderextends= OrderExtends::instance()->info(['order_id'=>$order['id']]);
        if($orderextends){
            $express_type=$orderextends['express_type'];
        }
        $address= empty($order['receive_info'])?NULL: json_decode($order['receive_info'],true);
        $responseData=[
            'face_token'    =>$face_token,
            'truename'      =>$face['name'],
            'idcard'        =>$face['idcard'],
            'mobile'        =>$face['mobile'],
            'address'       =>$address,
            'express_type'  =>$express_type,
            'memberinfo'    =>$member
        ];
        return Normal::returnCode(Normal::SUC, '操作成功',$responseData);
    }
    
    /**
     * 发布消息队列
     * @param array $msg
     */
    public function publishMsg( array $msg  = [] )
    {
        try {
            $handlerMessage = new FaceCenterMessageProducer($msg);
            $producer = ApplicationContext::getContainer()->get(Producer::class);
            $result = $producer->produce($handlerMessage,true);
            if( $result ) {
                return Normal::returnCode(Normal::SUC,"发布成功");
            }
            return Normal::returnCode(Normal::FAIL,"操作失败，请稍微再试[100000]");
        } catch ( \Throwable $e ) {
            return Normal::returnCode(Normal::FAIL,"操作失败，请稍微再试[{$e->getMessage()},{$e->getLine()},{$e->getFile()}]");
        }
    }
    
    public function consumerMessage(array $param ) {        
        return ShareCenterService::instance()->messageDeal($param);
    }
}
